﻿using System;
using JamesZhao.Engine.Graphics.Effects;
using JamesZhao.Engine.Graphics.Geometry;
using JamesZhao.Engine.Graphics.RenderStages;
using JamesZhao.Engine.Graphics.Surfaces;
using JamesZhao.Engine.Graphics.Visuals;
using SlimDX;
using SlimDX.Direct3D11;
using SlimDX.DXGI;
using Surface = JamesZhao.Engine.Graphics.Surfaces.Surface;

namespace JamesZhao.Engine.Graphics
{
    public class SurfaceVisualizer : RenderStage
    {
        private EffectVectorVariable _varSrcSize;
        private EffectResourceVariable _varSrcTexture;
        private EffectVectorVariable _varSrcSize2;
        private EffectResourceVariable _varSrcTexture2;
        private EffectScalarVariable _varScale;
        private EffectScalarVariable _varScale2;
        private string Key { get; set; }
        private ColorSurface SurfaceToVisualize { get; set; }

        public GpuProgram R32ToR8G8B8A8Effect { get; set; }
        public GpuProgram R16G16B16A16ToR8G8B8A8Effect { get; set; }

        public float Scale { get; set; }
        public SurfaceVisualizer(GraphicsDevice device,
            string name,
            ColorSurface surfaceToVisualize)
        {
            Key = name;
            SurfaceToVisualize = surfaceToVisualize;
            R32ToR8G8B8A8Effect = new GpuProgram(device, "Shaders/Conversion/R32ToR8G8B8A8.fx");
            R16G16B16A16ToR8G8B8A8Effect = new GpuProgram(device, "Shaders/Conversion/R16G16B16A16ToR8G8B8A8.fx");


            _varSrcSize = R32ToR8G8B8A8Effect.Effect.GetVariableByName("srcSize").AsVector();
            _varSrcTexture = R32ToR8G8B8A8Effect.Effect.GetVariableByName("srcTexture").AsResource();

            Scale = 1;

            _varSrcSize2 = R16G16B16A16ToR8G8B8A8Effect.Effect.GetVariableByName("srcSize").AsVector();
            _varSrcTexture2 = R16G16B16A16ToR8G8B8A8Effect.Effect.GetVariableByName("srcTexture").AsResource();

            _varScale = R32ToR8G8B8A8Effect.Effect.GetVariableByName("scale").AsScalar();
            _varScale2 = R16G16B16A16ToR8G8B8A8Effect.Effect.GetVariableByName("scale").AsScalar();

            var quadGeom = new GeometryBuffer(device);
            quadGeom.InitializeFrom(MeshData.LoadFullScreenQuad());
            FullScreenQuad = new MeshDrawable
                                 {
                                     GeometryBuffer = quadGeom
                                 };


        }

        protected MeshDrawable FullScreenQuad { get; set; }

        public override string Name
        {
            get { return Key; }
        }

        public bool Enabled { get; set; }

        protected override void OnRender(GraphicsDevice device, SwapChain swapChain, VisualsList visualsList, Camera camera)
        {
            if (Enabled)
            {
                if (SurfaceToVisualize.Format == Format.R32_Float)
                {
                    _varSrcSize.Set(new Vector2(SurfaceToVisualize.ActualSize.Width,
                                                SurfaceToVisualize.ActualSize.Height));
                    _varSrcTexture.SetResource(SurfaceToVisualize.ResourceView);
                    _varScale.Set(Scale);

                    device.ImmediateContext.OutputMerger.SetTargets(FinalColorSurface.TargetView);
                    FullScreenQuad.RenderWithGpuProgram(device, camera, R32ToR8G8B8A8Effect);
                }
                else if (SurfaceToVisualize.Format == Format.R16G16B16A16_Float)
                {
                    _varSrcSize2.Set(new Vector2(SurfaceToVisualize.ActualSize.Width,
                                                SurfaceToVisualize.ActualSize.Height));
                    _varSrcTexture2.SetResource(SurfaceToVisualize.ResourceView);
                    _varScale2.Set(Scale);

                    device.ImmediateContext.OutputMerger.SetTargets(FinalColorSurface.TargetView);
                    FullScreenQuad.RenderWithGpuProgram(device, camera, R16G16B16A16ToR8G8B8A8Effect);
                }

                else
                {
                    device.ImmediateContext.CopyResource(SurfaceToVisualize.Texture, FinalColorSurface.Texture);
                }
                swapChain.Present(0, PresentFlags.None);
            }
        }
    }
}